package cz.acies.uniql.sql;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;


import cz.acies.uniql.dialect.Dialect;
import cz.acies.uniql.metadata.DBMetaData;
import cz.acies.uniql.metadata.FieldMetaData;
import cz.acies.uniql.metadata.PrimaryKeyMetaData;
import cz.acies.uniql.metadata.TableMetaData;


public class CreateTable extends Query
{
	private static final long serialVersionUID = -2510067456038941890L;
	
	private String schema = null;
	private String tableName = null;
	private TableMetaData tbmd = null;
	private PrimaryKeyMetaData pkmd = null;
	private Map<String, String> params = null;
	
	/**
	 * Konstruktor tridy CreateTable.
	 */
	public CreateTable() {
	}

	/**
	 * Konstruktor tridy CreateTable.
	 * 
	 * @param dbmd - dbmd
	 */
	public CreateTable(DBMetaData dbmd) {
		super(dbmd);
	}

	/**
	 * Konstruktor tridy CreateTable.
	 * 
	 * @param dbmd - dbmd
	 * @param tableName - table name
	 */
	public CreateTable(DBMetaData dbmd, String tableName) {
		this(dbmd);
		this.setTableName(tableName);
	}

	/**
	 * Konstruktor tridy CreateTable.
	 * 
	 * @param dbmd - dbmd
	 * @param tbmd - tbmd
	 */
	public CreateTable(DBMetaData dbmd, TableMetaData tbmd) {
		this(dbmd);
		this.setTableMetaData(tbmd);
	}
	
	// -----  -----------------------------------------------------------------

	/* (non-Javadoc)
	 * @see cz.acies.uniql.sql.Query#toSQLString()
	 */
	public String toSQLString() throws Exception {
		return this.translate();
	}

	/* (non-Javadoc)
	 * @see cz.acies.uniql.sql.Query#translate()
	 */
	public String translate() throws Exception {
		try {
			Dialect dialect = this.getDialect();
			String schema = this.getSchema();
			StringBuffer sb = new StringBuffer();
			
			sb.append("CREATE TABLE ");
			if (schema != null && schema.length() > 0) {
				sb.append(dialect.CTI_LQ() + schema + dialect.CTI_RQ() + ".");
			}
			sb.append(dialect.CTI_LQ() + this.getTableName() + dialect.CTI_RQ() + " (\n");
			ArrayList<FieldMetaData> identities = new ArrayList<FieldMetaData>();
			if (tbmd != null) {
				for (int i = 0; i < tbmd.getFields().size(); i++) {
					FieldMetaData fmd = (FieldMetaData)tbmd.getFields().get(i);
					sb.append(fmd.transform());
					if (dialect.isIdentityAppnedIndex() && fmd.isAutoincrement()) {
						identities.add(fmd);
					}
					if (dialect.getPKAppendType() == 1) {
						if (pkmd != null) {
							String columnname = fmd.getName();
							String pkcolumnname = pkmd.getColumn();
							if (pkcolumnname.equals(columnname)) {
								sb.append("PRIMARY KEY ");
							}
						}
					}
					if (i < tbmd.getFields().size()-1) {
						sb.append(",\n");
					} else {
						if (pkmd != null && dialect.getPKAppendType() == 0) sb.append(",\n") ;
						else sb.append("\n");
					}
				}					
			}
			if (dialect.getPKAppendType() == 0) {
				if (pkmd != null) {
					String columnName = pkmd.getColumn();
					if (dialect.isPKConstrainted()) {
						sb.append(
							"\tCONSTRAINT "+
							dialect.CTI_LQ()+
							dialect.getPKConstraintKey(tableName, columnName)+
							dialect.CTI_RQ()+" "
						);
					}
					sb.append("PRIMARY KEY ( " + dialect.LQ() + columnName + dialect.RQ() + " ) ");
				}
			}
			if (dialect.isIdentityAppnedIndex()&& !identities.isEmpty()) {
				sb.append("\n,");
				for (Iterator<FieldMetaData> iterator = identities.iterator(); iterator.hasNext();) {
					FieldMetaData fmd = iterator.next();
					String columnName = fmd.getQuotedName();
					sb.append("KEY (" + columnName + ")");
					if (iterator.hasNext()) sb.append("\n,");
				}				
			}
			sb.append("\n)");
			if (params != null) {
				for (Iterator<String> it = params.keySet().iterator(); it.hasNext();) {
					String key = it.next();
					sb.append(key+"="+params.get(key));
					if (it.hasNext()) sb.append(" ");
					else sb.append(";"); 
				}
			}
			return sb.toString();
			
		} catch (Exception exc) {
			exc.printStackTrace();
		}
		return "";
	}

	// -----  -----------------------------------------------------------------
	
	/**
	 * Prida FieldMetaData.
	 * 
	 * @param fmd - fmd
	 * 
	 * @return vraci vytvori table
	 */
	public CreateTable addField(FieldMetaData fmd) {
		if (tbmd != null) {
			try { tbmd.addField(fmd); } catch (Exception exc) { exc.printStackTrace(); }
		}
		return this;
	}
	
	/**
	 * Prida FieldMetaData.
	 * 
	 * @param name - name
	 * @param sqlType - sql type
	 * @param size - size
	 * @param decimal - decimal
	 * @param isNull - is null
	 * @param value - value
	 * 
	 * @return vraci CreateTable 
	 */
	public CreateTable addField(String name, int sqlType, int size, int decimal, boolean isNull, String value) throws Exception {
		if (tbmd != null) {
			tbmd.addField(tableName, name, sqlType, size, decimal, isNull, value);
		}
		return this;
	}

	// -----  -----------------------------------------------------------------
	
	/**
	 * Navraci TableMetaData tabulky.
	 * 
	 * @return - vraci hodnotu table meta data
	 */
	public TableMetaData getTableMetaData() {
		return tbmd;
	}

	/**
	 * Zadava hodnotu TableMetaData tabulky.
	 * 
	 * @param tbmd - tbmd
	 * 
	 * @return vraci CreateTable
	 */
	public CreateTable setTableMetaData(TableMetaData tbmd) {
		this.tbmd = tbmd;
		this.tableName = this.tbmd.getName();
		//System.out.println("tableName = "+tableName);
		if (getDialect().isKeyword(tableName.toUpperCase())) {
			tableName = getDialect().getKeywordAlter(tableName.toUpperCase());
			this.tbmd.setName(tableName);
		}
		return this;
	}

	/**
	 * Navraci PrimaryKeyMetaData tabulky.
	 * 
	 * @return - vraci hodnotu PrimaryKeyMetaData
	 */
	public PrimaryKeyMetaData getPrimaryKeyMetaData() {
		return pkmd;
	}

	/**
	 * Zadava hodnotu PrimaryKeyMetaData tabulky.
	 * 
	 * @param pkmd - pkmd
	 * 
	 * @return vraci CreateTable
	 */
	public CreateTable setPrimaryKeyMetaData(PrimaryKeyMetaData pkmd) {
		this.pkmd = pkmd;
		return this;
	}
	
	/**
	 * Navraci schema DB.
	 * 
	 * @return - vraci schema DB
	 */
	public String getSchema() {
		if (this.schema == null) {
			if (this.getDialect() != null) {
				this.schema = this.getDialect().getSchema();	
			}
		}
		return schema;
	}

	/**
	 * Zada schema DB.
	 * 
	 * @param schema - nova hodnota schema DB
	 */
	public void setSchema(String schema) {
		this.schema = schema;
	}

	/**
	 * Navraci jmeno tabulky.
	 * 
	 * @return - vraci hodnotu jmeno tabulky
	 */
	public String getTableName() {
		return tableName;
	}

	/**
	 * Zadava jmeno tabulky.
	 * 
	 * @param tableName - table name
	 * 
	 * @return vraci CreateTable
	 */
	public CreateTable setTableName(String tableName) {
		System.out.println("CreateTable.setTableName().tableName = "+tableName);
		if (tbmd == null) {
			tbmd = new TableMetaData();
			tbmd.setDialect(this.getDialect());
		}
		if (getDialect().isKeyword(tableName.toUpperCase())) {
			tableName = getDialect().getKeywordAlter(tableName.toUpperCase());
		}
		//System.out.println("CreateTable.setTableName().tableName = "+tableName);
		this.tableName = tableName;		
		tbmd.setName(tableName);
		return this;
	}
	
	public Map<String, String> getParams() {
		return params;
	}

	public void setParams(Map<String, String> params) {
		this.params = params;
	}

}
